package com.kun.db.ds.simple;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
import cn.hutool.setting.dialect.Props;
import com.kun.alldb.classloader.DriverJarLoader;
import com.kun.db.DbRuntimeException;
import com.kun.db.dialect.DriverUtil;
import com.kun.db.ds.DSFactory;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/***
 * 简易数据源，没有使用连接池，仅供测试或打开关闭连接非常少的场合使用！
 *
 * @author loolly
 *
 */
public class SimpleDataSource extends AbstractDataSource {

    /**
     * 默认的数据库连接配置文件路径
     */
    public final static String DEFAULT_DB_CONFIG_PATH = "config/db.setting";

    // -------------------------------------------------------------------- Fields start
    private String driver; // 数据库驱动
    private String url; // jdbc url
    private String user; // 用户名
    private String pass; // 密码

    private String driverPath;// 动态加载jar路径

    // 连接配置
    private Properties connProps;

    private Driver driverInstance;
    // -------------------------------------------------------------------- Fields end

    /**
     * 获得一个数据源
     *
     * @param group 数据源分组
     * @return SimpleDataSource
     */
    synchronized public static SimpleDataSource getDataSource(String group) {
        return new SimpleDataSource(group);
    }

    /**
     * 获得一个数据源，无分组
     *
     * @return SimpleDataSource
     */
    synchronized public static SimpleDataSource getDataSource() {
        return new SimpleDataSource();
    }

    // -------------------------------------------------------------------- Constructor start

    /**
     * 构造
     */
    public SimpleDataSource() {
        this(null);
    }

    /**
     * 构造
     *
     * @param group 数据库配置文件中的分组
     */
    public SimpleDataSource(String group) {
        this(null, group);
    }

    /**
     * 构造
     *
     * @param setting 数据库配置
     * @param group   数据库配置文件中的分组
     */
    public SimpleDataSource(Setting setting, String group) {
        if (null == setting) {
            setting = new Setting(DEFAULT_DB_CONFIG_PATH);
        }
        final Setting config = setting.getSetting(group);
        if (MapUtil.isEmpty(config)) {
            throw new com.kun.db.DbRuntimeException("No DataSource config for group: [{}]", group);
        }

        init(//
                config.getAndRemoveStr(DSFactory.KEY_ALIAS_URL), //
                config.getAndRemoveStr(DSFactory.KEY_ALIAS_USER), //
                config.getAndRemoveStr(DSFactory.KEY_ALIAS_PASSWORD), //
                config.getAndRemoveStr(DSFactory.KEY_ALIAS_DRIVER)//
        );

        // 其它连接参数
        this.connProps = config.getProps(Setting.DEFAULT_GROUP);
    }

    /**
     * 构造
     *
     * @param url  jdbc url
     * @param user 用户名
     * @param pass 密码
     */
    public SimpleDataSource(String url, String user, String pass) {
        init(url, user, pass);
    }

    /**
     * 构造
     *
     * @param url    jdbc url
     * @param user   用户名
     * @param pass   密码
     * @param driver JDBC驱动类
     * @since 3.1.2
     */
    public SimpleDataSource(String url, String user, String pass, String driver) {
        init(url, user, pass, driver);
    }

    /**
     * 构造
     *
     * @param url    jdbc url
     * @param user   用户名
     * @param pass   密码
     * @param driver JDBC驱动类
     * @since 3.1.2
     */
    public SimpleDataSource(String url, String user, String pass, String driver,String driverPath) {
        init(url, user, pass, driver,driverPath);
    }


    // -------------------------------------------------------------------- Constructor end

    /**
     * 初始化
     *
     * @param url  jdbc url
     * @param user 用户名
     * @param pass 密码
     */
    public void init(String url, String user, String pass) {
        init(url, user, pass, null);
    }

    /**
     * 初始化
     *
     * @param url    jdbc url
     * @param user   用户名
     * @param pass   密码
     * @param driver JDBC驱动类，传入空则自动识别驱动类
     * @since 3.1.2
     */
    public void init(String url, String user, String pass, String driver) {
        this.driver = StrUtil.isNotBlank(driver) ? driver : DriverUtil.identifyDriver(url);
        try {
            Class.forName(this.driver);
        } catch (ClassNotFoundException e) {
            throw new DbRuntimeException(e, "Get jdbc driver [{}] error!", driver);
        }
        this.url = url;
        this.user = user;
        this.pass = pass;
    }

    public void init(String url, String user, String pass, String driver, String driverPath) {
        this.driver = StrUtil.isNotBlank(driver) ? driver : DriverUtil.identifyDriver(url);
        if (StrUtil.isBlank(driverPath)) {
            init(url, user, pass, driver);
        } else {
            // 驱动jar进行热插拔
            loadJarPlugin(driverPath, driver);
        }
        this.url = url;
        this.user = user;
        this.pass = pass;
    }

    private void loadJarPlugin(String driverPath, String driver) {
        try {
            this.driverInstance = DriverJarLoader.loadDriver(driverPath, driver);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    // -------------------------------------------------------------------- Getters and Setters start
    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPass() {
        return pass;
    }

    public void setPass(String pass) {
        this.pass = pass;
    }

    public Properties getConnProps() {
        return connProps;
    }

	public void setConnProps(Properties connProps) {
		this.connProps = connProps;
	}

    public void addConnProps(String key, String value) {
        if (null == this.connProps) {
            this.connProps = new Properties();
        }
        this.connProps.setProperty(key, value);
    }
    // -------------------------------------------------------------------- Getters and Setters end

    @Override
    public Connection getConnection() throws SQLException {
        final Props info = new Props();
        if (this.user != null) {
            info.setProperty("user", this.user);
        }
        if (this.pass != null) {
            info.setProperty("password", this.pass);
        }

        // 其它参数
        final Properties connProps = this.connProps;
        if (MapUtil.isNotEmpty(connProps)) {
            info.putAll(connProps);
        }
        if (driverInstance != null) {
            return driverInstance.connect(this.url, info);
        }
        return DriverManager.getConnection(this.url, info);
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return DriverManager.getConnection(this.url, username, password);
    }

    @Override
    public void close() {
        // Not need to close;
    }
}
